package me.zhengjie.cron;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.ObjectUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.config.RegisterAddressConfig;
import me.zhengjie.domain.PressingService;
import me.zhengjie.domain.TaskResultService;
import me.zhengjie.domain.UnbindingService;
import me.zhengjie.dto.Response;
import me.zhengjie.dto.sqlServer.*;
import me.zhengjie.domain.InBoundService;
import me.zhengjie.modbusTCP.LogisticsAreaTCP;
import me.zhengjie.repository.*;
import me.zhengjie.util.AnalyseCodeScannerUtil;
import me.zhengjie.wcs.WcsStatus;
import me.zhengjie.wcs.WmsToWcs;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.List;

@Slf4j
@Component
@RequiredArgsConstructor
public class LogisticsAreaCron {

    private final InBoundService inBoundService;
    private final PressingService pressingService;
    private final PalletRepository palletRepository;
    private final InBoundMissionRepository inBoundMissionRepository;
    private final OutBoundMissionRepository outBoundMissionRepository;
    private final WcsStatus wcsStatus;
    private final LogisticsAreaTCP logisticsAreaTCP;
    private final WmsTaskRepository wmsTaskRepository;
    private final WmsToWcs wmsToWcs;
    private final TaskResultService taskResultService;
    private final AnalyseCodeScannerUtil analyseCodeScannerUtil;
    private final UnbindingService unbindingService;

    private static final Logger inBoundLog = LoggerFactory.getLogger("inbound");
    private static final Logger pressingLog = LoggerFactory.getLogger("pressing");
    private final InventoryRepository inventoryRepository;



    /* * 物流区plc包括：
     * 入库口
     * 出库口
     * 压合区
     */

    /**
     * 入库区plc
     */
    @Scheduled(fixedDelay = 2000)
    public void listenInBoundPlc() {
        try {
            Integer sensorValue = logisticsAreaTCP.readHoldingRegisters(RegisterAddressConfig.inBoundShuntSensor);
            /*String scannerValue = String.valueOf(logisticsAreaTCP.readHoldingRegisters(RegisterAddressConfig.inBoundCodeScanner));*/
            String i = logisticsAreaTCP.readHoldingRegistersString(RegisterAddressConfig.inBoundShuntCodeScannerFirst);
            String j = logisticsAreaTCP.readHoldingRegistersString(RegisterAddressConfig.inBoundShuntCodeScannerSecond);

            String scannerValue = analyseCodeScannerUtil.analyseCodeScanner(i, j);
            log.info("库区分流口plc读值，传感器值：{}，扫码器值：{}", sensorValue, scannerValue);

            if (sensorValue != null && sensorValue == 1 && scannerValue != null) {

                // 回报plc读到码
                logisticsAreaTCP.writeWithRetry(RegisterAddressConfig.inBoundShuntIfSuccessReadCode, 1, 5);

                Pallet pallet = palletRepository.findPalletByPalletCode(scannerValue);
                log.info("此时库区分流口的载盘信息: {}", pallet);
                if (ObjectUtil.isEmpty(pallet.getProcesscardId())) {
                    // 回报plc读到码
                    logisticsAreaTCP.writeWithRetry(RegisterAddressConfig.inBoundShuntIfSuccessReadCode, 9, 5);
                    inBoundLog.error("该载盘没有绑定信息，载盘号：{}", scannerValue);
                    return;
                }
                Integer flowTo = pallet.getFlowTo();
                switch (flowTo) {
                    // 不进入立库
                    case 2:
                    case 3:
                        // 写入流动方向(不入库)
                        logisticsAreaTCP.writeWithRetry(RegisterAddressConfig.inBoundShuntFlowTo, 2, 5);
                        break;
                    // 进入立库
                    case 1:
                        // 写入流向信号(入库)
                        logisticsAreaTCP.writeWithRetry(RegisterAddressConfig.inBoundShuntFlowTo, 1, 5);
                        break;
                }
            }
        } catch (Exception e) {
            log.error("入库口定时器出错，错误原因：{}", e.getMessage());
        }
    }

    /**
     * 入库口最里面的传感器
     */
    @Scheduled(fixedDelay = 900000)
    public void inBoundSensorCron() {
        if (!wcsStatus.allowSendTask()) {
            // 码垛机异常，写入plc异常数值5
            logisticsAreaTCP.writeWithRetry(RegisterAddressConfig.inBoundIfSuccessReadCode, 5, 5);
            log.error("当前码垛机不能接收新任务");
        } else {

            Integer sensorValueSecond = logisticsAreaTCP.readHoldingRegisters(RegisterAddressConfig.inBoundSensorSecond);
            String i = logisticsAreaTCP.readHoldingRegistersString(RegisterAddressConfig.inBoundCodeScannerFirst);
            String j = logisticsAreaTCP.readHoldingRegistersString(RegisterAddressConfig.inBoundCodeScannerSecond);

            if (sensorValueSecond != null && sensorValueSecond == 1 && (i != null && j != null)) {
                i = new StringBuffer(i).reverse().toString();
                j = new StringBuffer(j).reverse().toString();
                String scannerValue = i.concat(j);
                if (!scannerValue.contains(" ")) {

                    log.info("入库口载盘号：{}", scannerValue);
                    Pallet pallet = palletRepository.findPalletByPalletCode(scannerValue);
                    if (pallet.getProcesscardId() == null && pallet.getFlowTo() == null) {
                        // 载盘可能出现没有绑定的情况，这个时候发送数值9，提示PLC
                        logisticsAreaTCP.writeWithRetry(RegisterAddressConfig.inBoundIfSuccessReadCode, 9, 5);
                        log.info("{}载盘未绑定，叠合台重新绑定！！", scannerValue);
                        return;
                    }
                    // 查找有没有正在进行的入库任务
                    TaskResult taskResult = taskResultService.findNowTaskResult(1);
                    // 查找库存中有没有相同载盘号的载盘
                    Inventory inventory = inventoryRepository.findInventoryByPalletId(palletRepository.findPalletByPalletCode(scannerValue).getId());
                    if (ObjectUtil.isEmpty(taskResult)) {
                        if (!ObjectUtil.isEmpty(inventory)) {
                            inBoundLog.error("库存中已存在{}的库存", scannerValue);
                            return;
                        }
                        // 查找最新的入库载盘任务
                        InBoundMission newInBoundMission = inBoundService.findNewInBoundMission();
                        if (newInBoundMission == null) {
                            Integer result = inBoundService.creatInBoundMission(scannerValue);
                            if (result == 2) {
                                // 满库，没有可用储位，回报plc异常数值3
                                logisticsAreaTCP.writeWithRetry(RegisterAddressConfig.inBoundIfSuccessReadCode, 3, 5);
                                inBoundLog.error("B区没有可分配的储位");
                            }
                        } else {
                            // 发送任务
                            inBoundService.sendInBoundTask(newInBoundMission);
                            // 回报plc读到码
                            logisticsAreaTCP.writeWithRetry(RegisterAddressConfig.inBoundIfSuccessReadCode, 1, 5);
                        }
                    } else {
                        // 有入库任务正在执行
                        logisticsAreaTCP.writeWithRetry(RegisterAddressConfig.inBoundIfSuccessReadCode, 4, 5);
                    }
                } else {
                    log.error("入库口扫码器返回值不符合规范，包含空字符：{}", scannerValue);
                }

            }
        }
    }

    /**
     * 1号压机，压合区plc
     */
    @Scheduled(fixedDelay = 1000)
    public void listenerOnePressingPlc() {
        try {
            Integer sensorValue = logisticsAreaTCP.readHoldingRegisters(RegisterAddressConfig.onePressingSensor);
            /*String scannerValue = String.valueOf(logisticsAreaTCP.readHoldingRegisters(RegisterAddressConfig.pressingCodeScanner));*/
            String i = logisticsAreaTCP.readHoldingRegistersString(RegisterAddressConfig.onePressingCodeScannerFirst);
            String j = logisticsAreaTCP.readHoldingRegistersString(RegisterAddressConfig.onePressingCodeScannerSecond);

            /*if (sensorValue!=null && sensorValue == 1 && ((i==null || j==null))){
                // 回报plc没有读到码
                logisticsAreaTCP.write(RegisterAddressConfig.pressingIfSuccessReadCode,2);
            }*/
            String scannerValue = analyseCodeScannerUtil.analyseCodeScanner(i, j);
            log.info("1号压机plc读值，传感器值：{}，扫码器值：{}", sensorValue, scannerValue);

            if (sensorValue != null && sensorValue == 1 && scannerValue != null) {

                pressingService.Pressing(scannerValue, 1);

                pressingLog.info("1号压机当前入压载盘编号为：{}，入压时间：{}", scannerValue, LocalDateTime.now());
            }
        } catch (Exception e) {
            log.error("1号压机定时器出错，错误原因：{}", e.toString());
        }
    }

    /**
     * 2号压机，压合区plc
     */
    @Scheduled(fixedDelay = 1000)
    public void listenerTwoPressingPlc() {
        try {
            Integer sensorValue = logisticsAreaTCP.readHoldingRegisters(RegisterAddressConfig.twoPressingSenor);
            /*String scannerValue = String.valueOf(logisticsAreaTCP.readHoldingRegisters(RegisterAddressConfig.pressingCodeScanner));*/
            String i = logisticsAreaTCP.readHoldingRegistersString(RegisterAddressConfig.twoPressingCodeScannerFirst);
            String j = logisticsAreaTCP.readHoldingRegistersString(RegisterAddressConfig.twoPressingCodeScannerSecond);

            /*if (sensorValue!=null && sensorValue == 1 && ((i==null || j==null))){
                // 回报plc没有读到码
                logisticsAreaTCP.write(RegisterAddressConfig.pressingIfSuccessReadCode,2);
            }*/

            String scannerValue = analyseCodeScannerUtil.analyseCodeScanner(i, j);
            log.info("2号压机plc读值，传感器值：{}，扫码器值：{}", sensorValue, scannerValue);

            if (sensorValue != null && sensorValue == 1 && scannerValue != null) {

                pressingService.Pressing(scannerValue, 2);

                pressingLog.info("2号压机当前入压载盘编号为：{}，入压时间：{}", scannerValue, LocalDateTime.now());
            }
        } catch (Exception e) {
            log.error("2号压机定时器出错，错误原因：{}", e.toString());
        }
    }

    /**
     * 出库口plc
     */
    @Scheduled(fixedDelay = 1000)
    public void listerOutBoundPlc() {
        try {
            Integer sensorValue = logisticsAreaTCP.readHoldingRegisters(RegisterAddressConfig.outBoundSensor);
            if (sensorValue != null && sensorValue == 1) {
                logisticsAreaTCP.writeWithRetry(RegisterAddressConfig.outBoundFlowTo, 1, 5);
            } else if (sensorValue != null && sensorValue == 0) {
                if (!wcsStatus.allowSendTask()) {
                    log.error("当前码垛机不能接收新出库任务");
                } else {
                    TaskResult taskResult = taskResultService.findNowTaskResult(2);
                    if (ObjectUtil.isEmpty(taskResult)) {
                        List<WmsTask> wmsTaskList = wmsTaskRepository.findWmsTasksByWcsTaskTypeAndStatusOrderByCreated(2, 0);
                        if (ObjectUtil.isEmpty(wmsTaskList)) {
                            return;
                        }
                        WmsTask nextTask = wmsTaskList.get(0);
                        if (!ObjectUtil.isEmpty(nextTask)) {
                            Response response = wmsToWcs.sendTask(nextTask);
                            int isSuccess = response.getIsSuccess();
                            if (isSuccess == 1) {
                                wmsTaskRepository.deleteById(nextTask.getId());

                            } else {
                                log.error("任务发送到wcs失败，失败的任务：{}", nextTask.getWmsTaskId());
                            }
                        } else {
                            log.info("出库单任务已全部发送到WCS");
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.error("出库定时器出错：{}", e.toString());
        }
    }

    /**
     * 二期一号压机二号压机分流口plc
     */
    @Scheduled(fixedDelay = 3000)
    public void listerPressFlowToOneOrTwoPlc() {
        try {
            Integer sensorValue = logisticsAreaTCP.readHoldingRegisters(RegisterAddressConfig.pressFlowSensor);
            /*String scannerValue = String.valueOf(logisticsAreaTCP.readHoldingRegisters(RegisterAddressConfig.pressingCodeScanner));*/
            String i = logisticsAreaTCP.readHoldingRegistersString(RegisterAddressConfig.pressFlowScannerFirst);
            String j = logisticsAreaTCP.readHoldingRegistersString(RegisterAddressConfig.pressFlowScannerSecond);

            String scannerValue = analyseCodeScannerUtil.analyseCodeScanner(i, j);
            pressingLog.info("压机分流口载盘号：{}", scannerValue);

            if (sensorValue != null && sensorValue == 1 && scannerValue != null) {
                i = new StringBuffer(i).reverse().toString();
                j = new StringBuffer(j).reverse().toString();

                // 回报plc读到码
                logisticsAreaTCP.writeWithRetry(RegisterAddressConfig.pressFlowIfSuccessReadCode, 1, 5);

                log.info("1号压机2号压机分流口plc读值，传感器值：{}，扫码器值：{}", sensorValue, scannerValue);

                Pallet pallet = palletRepository.findPalletByPalletCode(scannerValue);

                if (pallet.getFlowTo().equals(2)) {
                    // 进入1号压机
                    // 写入流向信号
                    logisticsAreaTCP.writeWithRetry(RegisterAddressConfig.pressFlowTo, 1, 5);
                } else if (pallet.getFlowTo().equals(3)) {
                    // 进入2号压机
                    // 写入流向信号
                    logisticsAreaTCP.writeWithRetry(RegisterAddressConfig.pressFlowTo, 2, 5);
                }
            }
        } catch (Exception e) {
            log.error("1,2号压机plc定时器错误，{}", e.toString());
        }
    }

    /**
     * 一号压机出压口
     */
    @Scheduled(fixedDelay = 1000)
    public void listenerOneOutPressingPlc() {
        try {
            Integer sensorValue = logisticsAreaTCP.readHoldingRegisters(RegisterAddressConfig.oneOutPressingSensor);
            /*String scannerValue = String.valueOf(logisticsAreaTCP.readHoldingRegisters(RegisterAddressConfig.pressingCodeScanner));*/
            String i = logisticsAreaTCP.readHoldingRegistersString(RegisterAddressConfig.oneOutPressingCodeScannerFirst);
            String j = logisticsAreaTCP.readHoldingRegistersString(RegisterAddressConfig.oneOutPressingCodeScannerSecond);

            /*if (sensorValue!=null && sensorValue == 1 && ((i==null || j==null))){
                // 回报plc没有读到码
                logisticsAreaTCP.write(RegisterAddressConfig.pressingIfSuccessReadCode,2);
            }*/

            String scannerValue = analyseCodeScannerUtil.analyseCodeScanner(i, j);

            log.info("1号出压plc读值，传感器值：{}，扫码器值：{}", sensorValue, scannerValue);
            if (sensorValue != null && sensorValue == 1 && scannerValue != null) {
                // 判断当前载盘所属的锅号id，判断是创建拆解单还是加入拆解单
                logisticsAreaTCP.writeWithRetry(RegisterAddressConfig.oneOutPressingIfSuccessReadCode, 1, 5);
                unbindingService.createOrderOrJoinOrder(scannerValue, 1);
            }
        } catch (Exception e) {
            log.error("1号出压定时器出错，错误原因：{}", e.toString());
        }
    }

    /**
     * 二号压机出压口
     */
    @Scheduled(fixedDelay = 1000)
    public void listenerTwoOutPressingPlc() {
        try {
            Integer sensorValue = logisticsAreaTCP.readHoldingRegisters(RegisterAddressConfig.twoOutPressingSensor);
            /*String scannerValue = String.valueOf(logisticsAreaTCP.readHoldingRegisters(RegisterAddressConfig.pressingCodeScanner));*/
            String i = logisticsAreaTCP.readHoldingRegistersString(RegisterAddressConfig.twoOutPressingCodeScannerFirst);
            String j = logisticsAreaTCP.readHoldingRegistersString(RegisterAddressConfig.twoOutPressingCodeScannerSecond);

            /*if (sensorValue!=null && sensorValue == 1 && ((i==null || j==null))){
                // 回报plc没有读到码
                logisticsAreaTCP.write(RegisterAddressConfig.pressingIfSuccessReadCode,2);
            }*/

            String scannerValue = analyseCodeScannerUtil.analyseCodeScanner(i, j);

            log.info("2号出压plc读值，传感器值：{}，扫码器值：{}", sensorValue, scannerValue);
            if (sensorValue != null && sensorValue == 1 && scannerValue != null) {

                // 判断当前载盘所属的锅号id，判断是创建拆解单还是加入拆解单
                logisticsAreaTCP.writeWithRetry(RegisterAddressConfig.twoOutPressingIfSuccessReadCode, 1, 5);
                unbindingService.createOrderOrJoinOrder(scannerValue, 2);

            }
        } catch (Exception e) {
            log.error("2号出压定时器出错，错误原因：{}", e.toString());
        }
    }

    /**
     * 一号缓存架plc
     */
    @Scheduled(fixedDelay = 2000)
    public void listenerNoOneCacheRackPlc() {

        try {
            Integer sensorValue = logisticsAreaTCP.readHoldingRegisters(RegisterAddressConfig.oneCacheRackSensor);
            String i = logisticsAreaTCP.readHoldingRegistersString(RegisterAddressConfig.oneCacheRackScannerFirst);
            String j = logisticsAreaTCP.readHoldingRegistersString(RegisterAddressConfig.oneCacheRackScannerSecond);

            String scannerValue = analyseCodeScannerUtil.analyseCodeScanner(i, j);

            if (sensorValue != null && sensorValue == 1 && scannerValue != null) {
                log.info("1号缓存架plc读值，传感器值：{}，扫码器值：{}", sensorValue, scannerValue);
                logisticsAreaTCP.writeWithRetry(RegisterAddressConfig.oneCacheRackIfSuccessReadCode, 1, 5);

                // 获取流向
                Integer flowTo = unbindingService.CacheRackFlowTo(scannerValue, 1);
                if (flowTo != null) {
                    logisticsAreaTCP.writeWithRetry(RegisterAddressConfig.oneCacheRackFlowTo, flowTo, 5);
                } else {

                }
            }
        } catch (Exception e) {
            log.error("1号缓存架定时器出错，错误原因：{}", e.toString());
        }
    }

    /**
     * 二号缓存架plc
     */
    @Scheduled(fixedDelay = 2000)
    public void listenerNoTwoCacheRackPlc() {

        try {
            Integer sensorValue = logisticsAreaTCP.readHoldingRegisters(RegisterAddressConfig.twoCacheRackSensor);
            String i = logisticsAreaTCP.readHoldingRegistersString(RegisterAddressConfig.twoCacheRackScannerFirst);
            String j = logisticsAreaTCP.readHoldingRegistersString(RegisterAddressConfig.twoCacheRackScannerSecond);

            String scannerValue = analyseCodeScannerUtil.analyseCodeScanner(i, j);

            if (sensorValue != null && sensorValue == 1 && scannerValue != null) {
                log.info("2号缓存架plc读值，传感器值：{}，扫码器值：{}", sensorValue, scannerValue);
                logisticsAreaTCP.writeWithRetry(RegisterAddressConfig.twoCacheRackIfSuccessReadCode, 1, 5);

                // 获取流向
                Integer flowTo = unbindingService.CacheRackFlowTo(scannerValue, 2);
                if (flowTo != null) {
                    logisticsAreaTCP.writeWithRetry(RegisterAddressConfig.twoCacheRackFlowTo, flowTo, 5);
                }
            }
        } catch (Exception e) {
            log.error("2号缓存架定时器出错，错误原因：{}", e.toString());
        }
    }




    /*public void listenOutBoundPlc(){
        try {
            int sensorValue = TCPUtil.readHoldingRegisters(master,RegisterAddressConfig.outBoundSensor);
            if (sensorValue == 1){
                // 出库口处有载盘，判断码垛机当前的任务状态，码垛机放货离开，启动滚筒线
                TCPUtil.write(master,RegisterAddressConfig.outBoundStartSignal,1);
            }else if (sensorValue == 0){
                String scannerValue = TCPUtil.readHoldingRegistersString(master,RegisterAddressConfig.outBoundCodeScanner);
                if (!scannerValue.isEmpty()) {}
                if (!scannerValue.isEmpty()) {
                    return;
                } else {
                    if (!wcsStatus.allowSendOutBoundMission("码垛机编码")) return;
                    else {
                        WmsTask nextTask = wmsTaskRepository.findWmsTasksByWcsTaskTypeAndStatusOrderByCreated(2,0).get(0);

                        //  根据wmsTask的wcsTaskId查找outBoundMission，根据outBoundMission的id查找orderId，根据orderId改变order的状态，改为工作中
                        OutBoundMission outBoundMission = outBoundMissionRepository.findOutBoundMissionByMissionCode(String.valueOf(nextTask.getWmsTaskId()));
                        Integer orderId = outBoundMission.getOutBoundOrderId();
                        OutBoundOrder outBoundOrder = outBoundOrderRepository.findOutBoundOrderById(orderId);
                        outBoundService.sendTaskToWcs(nextTask);

                        // 判断outBoundOrder的状态，如果状态是未开始，就把状态改为开始
                        if (outBoundOrder.getOrderStatus()==0){
                            outBoundOrderService.startOrder(orderId);
                        }

                        // 当前的出库单还有多少条任务
                        if (outBoundMissionService.findLastMissionCount(orderId)==0){
                            // 结束出库单
                            outBoundOrderService.finishOrder(orderId);
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.error("出库口plc异常",e.getMessage());
        }
    }*/
}
